<?php

/**
 * Classe User: gestisce l'utente e tutte le operazioni legate ad esso
 *
 * @author Stefano Poncini
 */
/**
 * Gestione per i namespace ***non funzionante***
 * 
 * namespace php\module;
 * use php\module\DB;
 * 
 */
// includo la classe DB
include("DB.class.php");
include("Login.class.php");
include("Mail.class.php");


class User {

    public $name;
    public $surname;
    public $email;
    public $username;
    public $password;
    public $activation_id;
    public $gender;
    public $date_of_birth;
    public $logins = array();
    public $avatar;
    public $last_login;
    public $registration_date;
    public $mail = array();
    public $type;
    public $banned;

    public function __construct() {
        
    }
    

    /**
     * Metodo printUsers: ricava tutti gli utenti dal database e li stampa
     */
    public function printUsers() {
        //$result = $sth->fetch(PDO::FETCH_ASSOC);

        $stmt = DB::getDBO()->prepare("SELECT * FROM user");
        $stmt->execute();
        $rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

        foreach ($rows as $row)
            foreach ($row as $key => $value)
                echo $key . ': ' . $value . '<br />';
    }

    /**
     * Metodo doLogin: cerca l'utente sul database con l'username e la password immessi, se esiste crea un istanza 
     * di User e lo mette in sessione
     * 
     * @param string $username
     * @param string $password
     * @return boolean
     */
    public function doLogin($username, $password) {
        $sql = "SELECT type, registration_date, avatar, name, surname, username, date_of_birth, count(*) as num from user where username = ? and password = md5(?) and banned = ?";

        $stmt = DB::getDBO()->prepare($sql);
        $stmt->execute(array($username, $password, 0));


        $result = $stmt->fetch();

        if ($result['num'] != 1) {
            return false;
        } else {

            // Carico i dati dell'utente nelle variabili di classe

            $this->name = $result['name'];
            $this->surname = $result['surname'];
            $this->username = $result['username'];
            $this->date_of_birth = $result['date_of_birth'];
            $this->avatar = $result['avatar'];
            $this->registration_date = $result['registration_date'];
            $this->last_login = new Login($_SERVER['REMOTE_ADDR'], date("Y-m-d H:i:s", time()));
            $this->type = $result['type'];


            // Login
            try {
                $sql = "INSERT INTO login(`id_login`,`ip_address`,`datetime`,`user`) values(null,?,?,?)";

                $stmt = DB::getDBO()->prepare($sql);
                $stmt->execute(array($_SERVER['REMOTE_ADDR'], date("Y-m-d H:i:s", time()), $this->username));
            } catch (PDOException $e) {
                
            }



            $this->setSession();
            header("Location: index.php");
            return true;
        }
    }

    /**
     * Metodo registerUser: crea un nuovo record sul database con i dati che gli vengono passati nell'oggetto $user
     * 
     * @param User $user
     * @return boolean
     */
    public static function registerUser($user) {

        try {
            $sql = "INSERT INTO user(`username`,`name`,`surname`,`email`,`password`,`activation_id`,`gender`,`date_of_birth`,`avatar`,`registration_date`,`type`) VALUES(?,?,?,?,?,?,?,?,?,?,?)";

            $stmt = DB::getDBO()->prepare($sql);
            $stmt->execute(array($user->username, ucfirst($user->name), ucfirst($user->surname), $user->email, $user->password, $user->activation_id, $user->gender, $user->date_of_birth, 'static/images/layout/new.jpg', date("Y-m-d H:i:s", time()), 1));

            return true;
        } catch (PDOException $e) {

            return false;
        }
    }

    /**
     * Metodo isLogged: controlla se esiste l'utente in sessione e ritorna true/false di conseguenza
     * 
     * @return boolean
     */
    public function isLogged() {
        (isset($_SESSION['user'])) ? $logged = true : $logged = false;

        return $logged;
    }
    
    public function checkUserOnline($user=null){
        if(isset($_SESSION['user']) && unserialize($_SESSION['user'])->username == (isset($user))?$user:$this->username)
            return true;
        else
            return false;
            
    }

    /**
     * Metodo setSession: mette l'utente in sessione
     */
    function setSession() {
        $_SESSION['user'] = serialize($this);
    }

    /**
     * Metodo doLogout: distrugge l'utente in sessione
     * 
     * @return boolean
     */
    public function doLogout() {
        if ($this->isLogged()) {
            session_destroy();
            header("Location: index.php");
            return true;
        } else {
            return false;
        }
    }

    /**
     * Metodo getFullName: ritorna una stringa concatenata con il nome e cognome dell'utente
     * 
     * @return string
     */
    public function getFullName() {


        return $this->name . ' ' . $this->surname;
    }

    /**
     * Metodo getFormattedAge: ritorna l'età in una stringa formattata
     * 
     * @return string
     */
    function getAge() {
        if ($this->date_of_birth != null && $this->date_of_birth != "") {
            $age = explode("-", $this->date_of_birth);
            $userYears = Util::getYears($age[0], $age[1], $age[2]);
            $userMonth = Util::getMonth($age[1]);

            return $userYears . ' anni (' . $age[2] . ' ' . $userMonth . ' ' . $age[0] . ')';
        }
    }

    /**
     * Metodo getUsername: ritorna l'username dell'utente
     * 
     * @return string
     */
    public function getUsername() {
        return $this->username;
    }

    /**
     * Metodo setLastVisit: imposta l'ora corrente come ultima visita dell'utente 
     * 
     * @return boolean
     */
    public function setLastVisit() {

        try {
            $sql = "UPDATE user SET last_visit = ? WHERE username = ?";
            $stmt = DB::getDBO()->prepare($sql);
            $stmt->execute(array(date("Y-m-d H:i:s", time()), $this->username));
            return true;
        } catch (PDOException $e) {

            return false;
        }
    }

    /**
     * Metodo getLastVisit: ritorna la data e ora dell'ultima visita dell'utente
     * 
     * @return datetime
     */
    public function getLastVisit($user) {
        $sql = "SELECT last_visit FROM user WHERE username = ?";

        $stmt = DB::getDBO()->prepare($sql);
        $stmt->execute(array((isset($user))?$user:$this->username));


        $result = $stmt->fetch();
        return $result['last_visit'];
    }

    /**
     * Metodo getStatus: ritorna ONLINE oppure OFFLINE se l'ultima visita risale a meno di due minuti rispetto all'ora corrente
     * 
     * @param type $last_visit
     * @return string
     */
    function isOnlineUser($user=null,$bool=null) {
        $str = "";
        $online = false;
        $last_visit = $this->getLastVisit($user);
        $time = Util::convertDateTime($last_visit);
        if($this->checkUserOnline()){
            if ((time() - $time) > 120) {
                $str = '<font size="1" color="#f20000"><b>OFFLINE</b></font>';
            } else {
                $str =  '<font size="1" color="#008000"><b>ONLINE</b></font>';
                $online = true;
            }
        }else{
            $str = '<font size="1" color="#f20000"><b>OFFLINE</b></font>';
        }
        
        if($bool){
            return $online;
        }else{
            return $str;
        }
    }

    /**
     * Metodo getNrLogins: ritorna il totale degli accessi effettuati dall'utente
     * 
     * @return int
     */
    public function getNrLogins() {
        $sql = "SELECT count(*) as nr_login FROM login WHERE user = ?";

        $stmt = DB::getDBO()->prepare($sql);
        $stmt->execute(array($this->username));


        $result = $stmt->fetch();

        return $result['nr_login'];
    }

    /**
     * Metodo editAvatar: aggiorna l'immagine profilo dell'utente
     * 
     * @param string $path
     * @return boolean
     */
    public function editAvatar($path) {

        try {
            $sql = "UPDATE user SET avatar = ? WHERE username = ?";
            $stmt = DB::getDBO()->prepare($sql);
            $stmt->execute(array($path, $this->username));
            return true;
        } catch (PDOException $e) {

            return false;
        }
    }

    /**
     * Metodo getAvatar: ritorna l'immagine profilo corrente dell'utente
     * 
     * @return string
     */
    public function getAvatar() {
        $sql = "SELECT avatar FROM user WHERE username = ?";

        $stmt = DB::getDBO()->prepare($sql);
        $stmt->execute(array($this->username));


        $result = $stmt->fetch();

        return $result['avatar'];
    }

    /**
     * Metodo changePassword: aggiorna la password dell'utente con quella nuova desiderata
     * 
     * @param string $newpw
     * @return boolean
     */
    public function changePassword($newpw) {
        try {
            $sql = "UPDATE user SET password = md5(?) WHERE username = ?";
            $stmt = DB::getDBO()->prepare($sql);
            $stmt->execute(array($newpw, $this->username));
            return true;
        } catch (PDOException $e) {

            return false;
        }
    }

    /**
     * Metodo loadUser: carica un utente dato uno username (per i profili)
     * @param string $username
     * @return boolean|\User
     */
    public static function loadUser($username) {   
        KLogger::instance("log", KLogger::DEBUG)->logInfo("Tentativo di caricamento utente " . $username);
        
        $user = new User();

        $sql = "SELECT banned, type, registration_date, avatar, name, surname, username, date_of_birth, count(*) as num from user where username = ?";

        $stmt = DB::getDBO()->prepare($sql);
        $stmt->execute(array($username));


        $result = $stmt->fetch();

        if ($result['num'] != 1) {
            KLogger::instance("log", KLogger::DEBUG)->logError('L\'utente ' . $username . " non è stato caricato");
            return false;
        } else {
            // Carico i dati dell'utente nelle variabili di classe
            KLogger::instance("log", KLogger::DEBUG)->logInfo("Utente " . $username . " caricato con successo");
            KLogger::instance("log", KLogger::DEBUG)->logInfo("Tentativo di caricamento logins per l'utente " . $username);
        
            $user->name = $result['name'];
            $user->surname = $result['surname'];
            $user->username = $result['username'];
            $user->date_of_birth = $result['date_of_birth'];
            $user->avatar = $result['avatar'];
            $user->registration_date = $result['registration_date'];
            $user->type = $result['type'];
            $user->banned = $result['banned'];

            $user->last_login = new Login($_SERVER['REMOTE_ADDR'], date("Y-m-d H:i:s", time()));

            $sql_ip = "select datetime, ip_address, count(*) as num from login where id_login = (select max(id_login) from login where user = ?)";

            $stmt_ip = DB::getDBO()->prepare($sql_ip);
            $stmt_ip->execute(array($username));


            $result_ip = $stmt_ip->fetch();

            if ($result_ip['num'] != 1) {
                KLogger::instance("log", KLogger::DEBUG)->logError("Errore durante il caricamento dei logins per l'utente " . $username);
            
                return false;
            } else {
                KLogger::instance("log", KLogger::DEBUG)->logInfo("Logins per l'utente " . $username . " caricati con successo");
        
                // Carico i dati dell'utente nelle variabili di classe
                $user->last_login = new Login($result_ip['ip_address'], $result_ip['datetime']);
            }


            return $user;
        }
    }

    /**
     * Metodo getMessages: ritorna tutti i messaggi privati di un utente
     * 
     * @return \Mail
     */
    public function getMessages() {
        $messages = array();
        $sql = "SELECT * FROM pm where (receiver = ? or sender = ?) and visible = ? and id_reply = ? order by id_message desc";
        $stmt = DB::getDBO()->prepare($sql);
        $stmt->execute(array($this->username, $this->username, 1, 0));

        while ($message = $stmt->fetch(PDO::FETCH_ASSOC)) {
            $messages[] = new Mail($message['id_message'], $message['title'], $message['text'], $message['datetime'], $message['sender'], $message['receiver']);
        }

        return $messages;
    }

    /**
     * Metodo deleteMessage: rende il messaggio non più visibile (mantengo tutti i dati sul db)
     * 
     * @param int $id
     * @return boolean
     */
    public function deleteMessage($id){
        try {
            $sql = "UPDATE pm SET visible = ? WHERE id_message = ?";
            $stmt = DB::getDBO()->prepare($sql);
            $stmt->execute(array(0,$id));
            return true;
        } catch (PDOException $e) {

            return false;
        }
        
    }
    
    /**
     * Metodo checkMessage: controllo se il messaggio è mio (controllo in fase di eliminazione di un messaggio) 
     * @param int $id
     * @return boolean
     */
    public function checkMessage($id){
        
        $sql = "SELECT count(id_message) as num FROM pm where receiver = ? and id_message = ?";
        $stmt = DB::getDBO()->prepare($sql);
        $stmt->execute(array($this->username, $id));

        $result = $stmt->fetch();

        if ($result['num'] != 1) {
            return false;
        } else {
            return true;
        }
    }
    
    /**
     * Metodo getMessageReplies: ricavo i messaggi di risposta di un determinato PM
     * 
     * @param int $id
     * @return \Mail
     */
    public function getMessageReplies($id){
        $replies = array();
        $sql = "SELECT * FROM pm where id_message = ? or id_reply = ? order by id_message asc";
        $stmt = DB::getDBO()->prepare($sql);
        $stmt->execute(array($id, $id));

        while ($reply = $stmt->fetch(PDO::FETCH_ASSOC)) {
            $replies[] = new Mail($reply['id_message'], $reply['title'], $reply['text'], $reply['datetime'], $reply['sender'], $reply['receiver']);
        }

        return $replies;
    }
    
    /**
     * Metodo sendPMReply: invio messaggio di risposta
     * 
     * @param string $text
     * @param int $receiver
     * @param int $id_parent
     * @return boolean
     */
    public function sendPMReply($text, $receiver, $id_parent) {

        try {
            $sql = "INSERT INTO pm(`id_message`,`title`,`text`,`datetime`,`sender`,`receiver`,`visible`,`id_reply`,`sender_read`,`receiver_read`) VALUES(?,?,?,?,?,?,?,?,?,?)";

            $stmt = DB::getDBO()->prepare($sql);
            $stmt->execute(array(null, "", $text, date("Y-m-d H:i:s", time()), $this->username, $receiver, 1, $id_parent, 1, 0));

            return true;
        } catch (PDOException $e) {

            return false;
        }
    }
    
    /**
     * Metodo sendPM: invio di un PM
     *  
     * @param string $title
     * @param string $text
     * @param int $receiver
     * @return boolean
     */
    public function sendPM($title, $text, $receiver) {

        try {
            
            DB::getDBO()->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
            $sql = "INSERT INTO pm(`id_message`,`title`,`text`,`datetime`,`sender`,`receiver`,`visible`,`id_reply`,`sender_read`,`receiver_read`) VALUES(?,?,?,?,?,?,?,?,?,?)";

            $stmt = DB::getDBO()->prepare($sql);
            $stmt->execute(array(null, $title, $text, date("Y-m-d H:i:s", time()), $this->username, $receiver, 1, 0, 1, 0));
            
            return true;
        } catch (PDOException $e) {

            return false;
        }
    }
    
    /**
     * Metodo checkUnreadPM: ritorna il numero di messaggi non letti in un PM
     * 
     * @param int $id
     * @return int
     */
    public function checkUnreadPM($id){
        $sql = "SELECT count(id_message) as num FROM pm where (id_message = ? or id_reply = ?) and receiver_read = ? and (receiver = ? and sender != ?)";
        $stmt = DB::getDBO()->prepare($sql);
        $stmt->execute(array($id, $id, 0, $this->username, $this->username));

        $result = $stmt->fetch();

        if ($result['num'] != 0) {
            return $result['num'];
        } else {
            return 0;
        }
        
    }
    
    /**
     * Metodo setPMRead: imposto il messaggio allo stato "letto" una volta che l'utente lo legge
     * 
     * @param int $id_parent
     * @return boolean
     */
    public function setPMRead($id_parent){
        try {
            $sql = "UPDATE pm SET receiver_read = ? WHERE (id_reply = ? or id_message = ?) and sender != ? ";
            $stmt = DB::getDBO()->prepare($sql);
            $stmt->execute(array(1,$id_parent,$id_parent, $this->username));
            return true;
        } catch (PDOException $e) {

            return false;
        }
        
    }
    
    /**
     * Metodo getPMReceiver: ritorna il destinatario di un determinato PM
     * 
     * @param int $id_message
     * @return type
     */
    public function getPMReceiver($id_message){
        $sql = "SELECT sender, receiver from pm where id_message = ?";
        $stmt = DB::getDBO()->prepare($sql);
        $stmt->execute(array($id_message));

        $result = $stmt->fetch();
        
        if($result['sender'] == $this->username)
            return $result['receiver'];
        else
            return $result['sender'];
    }
    
    /**
     * Metodo getCreatorImage: ritorna il percorso dell'immagine di un determinato utente
     * 
     * @param string $creator
     * @static
     * @return string
     */
    public static function getCreatorImage($creator){
        $sql = "SELECT avatar from user where username = ?";
        $stmt = DB::getDBO()->prepare($sql);
        $stmt->execute(array($creator));

        $result = $stmt->fetch();
        
        return $result['avatar'];
    }
    
    /**
     * Metodo getNrPosts: ritorna il numero dei post totali dell'utente
     * 
     * @return int
     */
    public function getNrPosts(){
        $sql = "SELECT count(id_post) as num_posts from post where creator = ?";
        $stmt = DB::getDBO()->prepare($sql);
        $stmt->execute(array($this->username));

        $result = $stmt->fetch();
        
        return $result['num_posts'];
    }
    
    /**
     * Metodo getUserType: ritorna il tipo di account dell'utente (admin, user, moderatore, etc)
     * 
     * @return string
     */
    public function getUserType(){
        $sql = "SELECT ut.type from user u , user_type ut where u.type = ut.id_type and u.type = ?";
        $stmt = DB::getDBO()->prepare($sql);
        $stmt->execute(array($this->type));

        $result = $stmt->fetch();
        
        return $result['type'];
    }
    
    /**
     * Metodo isAdmin: ritorna true o false se è admin o meno
     * 
     * @return boolean
     */
    public function isAdmin(){
        if($this->getUserType() == 'admin'){
            return true;
        }else{
            return false;
        }
    }
    
    /**
     * Metodo ban: blocca e sblocca un utente
     * 
     * @param string $username
     * @return boolean
     */
    public static function ban($username){
        try {
            $sql = "UPDATE user SET banned = !banned WHERE username = ?";
            $stmt = DB::getDBO()->prepare($sql);
            $stmt->execute(array($username));
            return true;
        } catch (PDOException $e) {

            return false;
        }
    }
    
    /**
     * Metodo getAccess: ritorna tutti gli utenti che han fatto l'accesso da un determinato indirizzo IP
     * @param string $username
     * @return \Login
     */
    public static function getAccess($username){
        $access = array();
        $sql = "SELECT * FROM login where user = ? order by datetime desc";
        $stmt = DB::getDBO()->prepare($sql);
        $stmt->execute(array($username));

        while ($login = $stmt->fetch(PDO::FETCH_ASSOC)) {
            $access[] = new Login($login['ip_address'], $login['datetime'], $login['id_login']);
        }

        return $access;
    }
    
    /**
     * Metodo admin: promuove amministratore o rimuove un amministratore
     * 
     * @param string $username
     * @param int $type
     * @return boolean
     */
    public static function admin($username, $type){
        try {
            $sql = "UPDATE user SET type = ? WHERE username = ? ";
            $stmt = DB::getDBO()->prepare($sql);
            $stmt->execute(array($type,$username));
            return true;
        } catch (PDOException $e) {

            return false;
        }
    }
    
    public static function getLastRegisteredUser() {   
        KLogger::instance("log", KLogger::DEBUG)->logInfo("Tentativo di caricamento ultimo utente registrato");
        
        $user = new User();

        $sql = "SELECT name, surname, username, avatar from user order by registration_date limit 1";

        $stmt = DB::getDBO()->prepare($sql);
        $stmt->execute();


        $result = $stmt->fetch();

        // Carico i dati dell'utente nelle variabili di classe
        KLogger::instance("log", KLogger::DEBUG)->logInfo("Utente " . $result['username'] . " caricato come ultimo registrato");

        $user->name = $result['name'];
        $user->surname = $result['surname'];
        $user->username = $result['username'];
        $user->avatar = $result['avatar'];

        return $user;
    }
    
    public static function getBirthdayUsers(){
        KLogger::instance("log", KLogger::DEBUG)->logInfo("Caricamento utenti che fanno il compleanno oggi");
        
        
        $users = array();
        $sql = "SELECT name, surname, username, avatar from user ";

        $stmt = DB::getDBO()->prepare($sql);
        $stmt->execute();

        if($stmt->rowCount() != 0){
            while ($usr = $stmt->fetch(PDO::FETCH_ASSOC)) {
                $user = new User();
                $user->name = $usr['name'];
                $user->surname = $usr['surname'];
                $user->username = $usr['username'];
                $user->avatar = $usr['avatar'];
                $users[] = $user;
            }
            // Carico i dati dell'utente nelle variabili di classe
            KLogger::instance("log", KLogger::DEBUG)->logInfo("Utenti che compiono gli anni caricati");

        }else{
            
            return false;
        }
        return $users;
    }
    
    public static function getOnlineUsers(){
        KLogger::instance("log", KLogger::DEBUG)->logInfo("Caricamento utenti che fanno il compleanno oggi");
        
        
        $users = array();
        $sql = "SELECT * from user ";

        $stmt = DB::getDBO()->prepare($sql);
        $stmt->execute();

        if($stmt->rowCount() != 0){
            while ($usr = $stmt->fetch(PDO::FETCH_ASSOC)) {
                $user = new User();
                $user->name = $usr['name'];
                $user->surname = $usr['surname'];
                $user->username = $usr['username'];
                $user->date_of_birth = $usr['date_of_birth'];
                $user->avatar = $usr['avatar'];
                $user->registration_date = $usr['registration_date'];
                $user->type = $usr['type'];
                
                if($user->isOnlineUser() == '<font size="1" color="#008000"><b>ONLINE</b></font>'){
                    $users[] = $user;
                } 
                
                
            }
            // Carico i dati dell'utente nelle variabili di classe
            KLogger::instance("log", KLogger::DEBUG)->logInfo("Utenti che compiono gli anni caricati");

        }else{
            
            return false;
        }
        return $users;
    }
}

?>
